package com.gscitysfy.cus.drain.modules.pipe.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gscitysfy.cloudfrmwk.assistant.domain.Result;
import com.gscitysfy.cloudfrmwk.security.utils.SecurityUtils;
import com.gscitysfy.cus.drain.constants.DicConstant;
import com.gscitysfy.cus.drain.constants.RedisKeyConstant;


import com.gscitysfy.cus.drain.modules.pipe.entity.DrainPipeNetworkJob;
import com.gscitysfy.cus.drain.modules.pipe.entity.DrainPipeNetworkPage;
import com.gscitysfy.cus.drain.modules.pipe.entity.DrainPipeNetworkPlan;
import com.gscitysfy.cus.drain.modules.pipe.mapper.DrainPipeNetworkJobMapper;
import com.gscitysfy.cus.drain.modules.pipe.mapper.DrainPipeNetworkPlanMapper;
import com.gscitysfy.cus.drain.modules.pipe.service.ICifrsPipeMnPipelineService;
import com.gscitysfy.cus.drain.modules.pipe.service.IDrainPipeNetworkPageService;
import com.gscitysfy.cus.drain.modules.pipe.service.IDrainPipeNetworkPlanService;
import com.gscitysfy.cus.drain.modules.pipe.vo.DrainPipeNetworkPlanExcel;
import com.gscitysfy.cus.drain.utils.DateUtil;
import com.gscitysfy.cus.drain.utils.HttpResponseUtil;
import com.gscitysfy.cus.drain.utils.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.commands.BinaryScriptingCommandsPipeline;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author admin
 * @since 2022-11-15 10:49:35
 */
@Service
public class DrainPipeNetworkPlanServiceImpl extends ServiceImpl<DrainPipeNetworkPlanMapper, DrainPipeNetworkPlan> implements IDrainPipeNetworkPlanService {

    @Resource
    private IDrainPipeNetworkPageService pageService;

    @Resource
    private ICifrsPipeMnPipelineService pipelineService;

    @Resource
    private DrainPipeNetworkJobMapper jobMapper;

    @Resource
    private RedisUtil redisUtil;

    /**
     * 删除计划
     * @param ids
     * @return
     */
    @Override
    public Result<Boolean> del(String ids) {
        if(StringUtils.isEmpty(ids)){
            return Result.failure("请选择计划id进行删除");
        }
        LambdaUpdateWrapper<DrainPipeNetworkPlan> query = new LambdaUpdateWrapper<>();
        List<Long> idList = Arrays.stream(ids.split(StrUtil.COMMA)).map(Long::parseLong).collect(Collectors.toList());
        query.in(DrainPipeNetworkPlan::getCmKid, idList).set(DrainPipeNetworkPlan::getCmUsable, true);

        return Result.content(this.update(query));
    }


    /**
     * 审核检测计划
     * @param plan
     * @return
     */
    @Override
    public Result<Boolean> audit(DrainPipeNetworkPlan plan) {
        LambdaUpdateWrapper<DrainPipeNetworkPlan> query = new LambdaUpdateWrapper<>();
        query.eq(DrainPipeNetworkPlan::getCmKid, plan.getCmKid())
                .set(DrainPipeNetworkPlan::getCmPlanAuditStatus, plan.getCmPlanAuditStatus())
                .set(DrainPipeNetworkPlan::getCmPlanAuditOpinion, plan.getCmPlanAuditOpinion())
                .set(DrainPipeNetworkPlan::getCmPlanAuditTime, new Date())
                .set(DrainPipeNetworkPlan::getCmPlanAuditPeople, SecurityUtils.getPrincipal().getName());

        return Result.content(this.update(query));
    }


    /**
     * 项目新增
     * @param plan
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> andOrUpdate(DrainPipeNetworkPlan plan) {
        if(Objects.isNull(plan.getCmKid())){
            plan.setCmPlanNo(this.createPlanNo());
            this.save(plan);
        }else{
            this.updateById(plan);
            //删除关联的管道
            LambdaQueryWrapper<DrainPipeNetworkPage> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DrainPipeNetworkPage::getCmPlanId, plan.getCmKid());
            pageService.remove(queryWrapper);
        }
        //新增管线数据
        List<DrainPipeNetworkPage> pipList = plan.getPipList();
        for (DrainPipeNetworkPage pip : pipList){
            pip.setCmKid(null);
            pip.setCmPlanId(plan.getCmKid());
            //待检测
            pip.setCmPipeDetectionStatus(0);
        }
        return Result.content(pageService.saveBatch(pipList));
    }

    /**
     * 查询管道信息（补充所在道路信息）
     * @param plan
     * @return
     */
    @Override
    public Result<List<DrainPipeNetworkPage>> findPip(DrainPipeNetworkPlan plan) {
        List<DrainPipeNetworkPage> pipList = plan.getPipList();

        List<String> guids = pipList.stream().map(DrainPipeNetworkPage::getCmPipeNo).collect(Collectors.toList());

        if(!guids.isEmpty()){
            List<DrainPipeNetworkPage> pips = pipelineService.findPip(guids);
            Map<String, String> guidMap = new HashMap<>(16);

            pips.forEach(pip -> {
                guidMap.put(pip.getCmPipeNo(), pip.getCmPipeRoad());
            });
            //设置所在道路，坑
            pipList.forEach(pip -> {
                String road = guidMap.get(pip.getCmPipeNo());
                pip.setCmPipeRoad(road);
            });

            return Result.content(pipList);
        }
        return Result.content(null);
    }

    /**
     * 获取监测计划列表
     * @param page
     * @param plan
     * @return
     */
    @Override
    public Result<IPage<DrainPipeNetworkPlan>> findPlanList(Page<DrainPipeNetworkPlan> page, DrainPipeNetworkPlan plan) {

        LambdaQueryWrapper<DrainPipeNetworkPlan> queryWrapper = this.createQuery(plan);

        return Result.content(this.page(page, queryWrapper));
    }

    /**
     * 创建查询条件
     * @param plan
     * @return
     */
    private LambdaQueryWrapper<DrainPipeNetworkPlan> createQuery(DrainPipeNetworkPlan plan){
        LambdaQueryWrapper<DrainPipeNetworkPlan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StringUtils.isNoneEmpty(plan.getCmPlanPipeType()), DrainPipeNetworkPlan::getCmPlanPipeType, plan.getCmPlanPipeType())
                .eq(Objects.nonNull(plan.getCmPlanFinishStatus()), DrainPipeNetworkPlan::getCmPlanFinishStatus, plan.getCmPlanFinishStatus())
                .eq(Objects.nonNull(plan.getCmPlanAuditStatus()), DrainPipeNetworkPlan::getCmPlanAuditStatus, plan.getCmPlanAuditStatus())
                .ge(Objects.nonNull(plan.getStartDate()), DrainPipeNetworkPlan::getCmPlanStartDate, plan.getStartDate())
                .le(Objects.nonNull(plan.getEndDate()), DrainPipeNetworkPlan::getCmPlanStartDate, plan.getEndDate())
                .like(StringUtils.isNotEmpty(plan.getCmPlanNo()), DrainPipeNetworkPlan::getCmPlanNo, plan.getCmPlanNo())
                .like(StringUtils.isNotEmpty(plan.getCmPlanName()), DrainPipeNetworkPlan::getCmPlanName, plan.getCmPlanName());
        if (StringUtils.isNotEmpty(plan.getIds())){
            queryWrapper.clear();
            List<Long> idList = Arrays.stream(plan.getIds().split(StrUtil.COMMA)).map(Long::parseLong).collect(Collectors.toList());

            queryWrapper.in(DrainPipeNetworkPlan::getCmKid, idList);
        }
        queryWrapper.eq(DrainPipeNetworkPlan::getCmUsable, false);
        queryWrapper.orderByDesc(DrainPipeNetworkPlan::getCmAddtime);
        return queryWrapper;
    }

    /**
     * 导出检测计划
     * @param response
     * @param plan
     */
    @Override
    public void export(HttpServletResponse response, DrainPipeNetworkPlan plan) throws IOException {
        List<DrainPipeNetworkPlan> pipList = this.list(this.createQuery(plan));

        Map<Object, Object> planType = redisUtil.hmget(RedisKeyConstant.DATA_DICT_KEY + DicConstant.PLAN_PIPE_TYPE);

        List<DrainPipeNetworkPlanExcel> excelList = new ArrayList<>(16);
        pipList.forEach(pip -> {
            DrainPipeNetworkPlanExcel excel = new DrainPipeNetworkPlanExcel();
            BeanUtils.copyProperties(pip, excel);

            excel.setCmPlanPipeType(planType.get(pip.getCmPlanPipeType()).toString());
            excelList.add(excel);
        });

        HttpResponseUtil.setResponseHeaders(response, "检测计划记录.xlsx");
        EasyExcel.write(response.getOutputStream(), DrainPipeNetworkPlanExcel.class)
                .sheet("检测计划")
                .doWrite(() -> excelList);
    }

    /**
     * 查看检测计划详情
     * @param cmKid
     * @return
     */
    @Override
    public Result<DrainPipeNetworkPlan> view(Long cmKid) {
        DrainPipeNetworkPlan plan = this.getById(cmKid);

        LambdaQueryWrapper<DrainPipeNetworkPage> pipQuery = new LambdaQueryWrapper<>();
        pipQuery.eq(DrainPipeNetworkPage::getCmPlanId, cmKid);

        //关联管道数据
        List<DrainPipeNetworkPage> pipList = this.pageService.list(pipQuery);
        plan.setPipList(pipList);

        LambdaQueryWrapper<DrainPipeNetworkJob> jobQuery = new LambdaQueryWrapper<>();
        jobQuery.eq(DrainPipeNetworkJob::getCmPlanId,cmKid);

        DrainPipeNetworkJob job = jobMapper.selectOne(jobQuery);

        plan.setJob(job);
        return Result.content(plan);
    }

    /**
     * 派发任务
     * @param job
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> createJob(DrainPipeNetworkJob job) {
        String jobNo = this.createJobNo();
        job.setCmJobNo(jobNo); job.setCmJobStatus(0);
        jobMapper.insert(job);
        //更新关联的管道任务id
        LambdaUpdateWrapper<DrainPipeNetworkPage> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(DrainPipeNetworkPage::getCmPlanId, job.getCmPlanId()).set(DrainPipeNetworkPage::getCmJobId, job.getCmKid())
                .eq(DrainPipeNetworkPage::getCmPipeDetectionStatus, 0);
        pageService.update(updateWrapper);

        LambdaUpdateWrapper<DrainPipeNetworkPlan> update = new LambdaUpdateWrapper<>();
        update.eq(DrainPipeNetworkPlan::getCmKid, job.getCmPlanId()).set(DrainPipeNetworkPlan::getCmPlanDistributionStatus, 1);


        return Result.content(this.update(update));
    }

    /**
     * 创建检测计划编号
     * @return
     */
    private String createPlanNo(){
        String nextNo = "JCJH" + DateUtil.formatDate(new Date(), DateUtil.yyyy_MM_dd_HH_mm);
        LambdaQueryWrapper<DrainPipeNetworkPlan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.likeRight(DrainPipeNetworkPlan::getCmPlanNo, nextNo).orderByDesc(DrainPipeNetworkPlan::getCmAddtime).last("limit 1");
        DrainPipeNetworkPlan plan = this.getOne(queryWrapper);
        if (!Objects.isNull(plan)){
            String preNo = plan.getCmPlanNo();
            String num = preNo.substring(preNo.length() - 3);
            String time = preNo.substring(0, preNo.length() - 3);
            DecimalFormat format = new DecimalFormat("000");
            //TODO 不考虑超过999的情况
            nextNo = time + format.format(Integer.parseInt(num) + 1);
        }else{
            nextNo = nextNo + "001";
        }
        return nextNo;
    }

    /**
     * 创建检测任务编号
     * @return
     */
    private String createJobNo(){
        String nextNo = "JCRW" + DateUtil.formatDate(new Date(), DateUtil.yyyy_MM_dd_HH_mm);
        LambdaQueryWrapper<DrainPipeNetworkJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.likeRight(DrainPipeNetworkJob::getCmJobNo, nextNo).orderByDesc(DrainPipeNetworkJob::getCmAddtime).last("limit 1");
        DrainPipeNetworkJob job = jobMapper.selectOne(queryWrapper);
        if (!Objects.isNull(job)){
            String preNo = job.getCmJobNo();
            String num = preNo.substring(preNo.length() - 3);
            String time = preNo.substring(0, preNo.length() - 3);
            DecimalFormat format = new DecimalFormat("000");
            //TODO 不考虑超过999的情况
            nextNo = time + format.format(Integer.parseInt(num) + 1);
        }else{
            nextNo = nextNo + "001";
        }
        return nextNo;
    }

    /**
     * 查询管网覆盖率
     * @param ids
     * @return
     */
    @Override
    public Result<String> viewCoverage(String ids) {
        if(StringUtils.isEmpty(ids)){
            return Result.failure("请选择一个或多个检测计划！");
        }

        List<Long> idList = Arrays.stream(ids.split(StrUtil.COMMA)).map(Long::parseLong).collect(Collectors.toList());

        LambdaQueryWrapper<DrainPipeNetworkPage> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(DrainPipeNetworkPage::getCmPlanId, idList);
        List<DrainPipeNetworkPage> pipList = pageService.list(queryWrapper);

        List<String> guids = pipList.stream().map(DrainPipeNetworkPage::getCmPipeNo).collect(Collectors.toList());
        String pipType = "";
        if(!pipList.isEmpty()){
            DrainPipeNetworkPlan plan = this.getById(pipList.get(0).getCmPlanId());
            pipType = plan.getCmPlanPipeType();
        }
        //计算覆盖率
        double coverage = pipelineService.coverage(pipType, guids);

        String percentage = new Formatter().format("%.2f", coverage * 100).toString().concat("%");
        return Result.content(percentage);
    }

    /**
     * 根究guid查询管道信息
     * @param guid
     * @return
     */
    @Override
    public Result<DrainPipeNetworkPage> pipInfo(String guid) {
        LambdaQueryWrapper<DrainPipeNetworkPage> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DrainPipeNetworkPage::getCmPipeNo, guid);

        DrainPipeNetworkPage pipe = pageService.getOne(queryWrapper);
        return Result.content(pipe);
    }


}
